﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Common.Protocol.Data;
using HK.Core.Utils;
using UnityEngine;
using HCompareOptions = HK.Core.Common.Protocol.Data.CompareOptions;

namespace HK.Core.Common.Data
{

    /// <summary>
    /// 文件后缀
    /// </summary>
    [Serializable]
    public sealed class FileExtension : JsonData<FileExtension>, IFileExtension, IEquatable<FileExtension>
    {

#region Create

        /// <summary>
        /// 创建文件后缀信息
        /// </summary>
        /// <param name="iExtension">文件后缀</param>
        /// <param name="iTitleDesc">文件后缀描述</param>
        /// <returns>文件后缀信息</returns>
        public static FileExtension Create(string iExtension, string iTitleDesc = null)
        {
            return new FileExtension { Extension = iExtension, TitleDesc = iTitleDesc };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private FileExtension() {}
        
        [SerializeField]
        private string titleDesc = null;
        /// <summary>
        /// 标题描述
        /// </summary>
        public string TitleDesc
        {
            get => titleDesc;
            private set => titleDesc = value;
        }
        
        [SerializeField]
        private string extension = null;
        /// <summary>
        /// 后缀
        /// <para>* 格式:unity,jpg等</para>
        /// </summary>
        public string Extension 
        {
            get => extension;
            private set => extension = value;
        }
        
        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => $"{titleDesc}_{Extension}";

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => !string.IsNullOrEmpty(extension);

#region Equal
        
        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iOther">other</param>
        /// <returns>true:相同; false:不同;</returns>
        public bool Equals(FileExtension iOther)
        {
            if (null == iOther || !iOther.Valid) return false;

            if (UtilsString.Diff(extension, iOther.Extension)) return false;
            if (UtilsString.Diff(titleDesc, iOther.TitleDesc)) return false;
            return true;
        }

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IFileExtension fileExt)
            {
                titleDesc = UpdateValue(titleDesc, fileExt.TitleDesc, iImport);
                extension = UpdateValue(extension, fileExt.Extension, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            titleDesc = null;
            extension = null;
        }
    }

    /// <summary>
    /// 文件后缀列表
    /// </summary>
    [Serializable]
    public sealed class FileExtensions : ListJsonData<FileExtensions, FileExtension>, IFileExtensions
    {

#region Create

        /// <summary>
        /// 创建文件后缀列表
        /// </summary>
        /// <param name="iExtensions">文件后缀列表</param>
        /// <returns>文件后缀列表</returns>
        public static IFileExtensions Create(List<FileExtension> iExtensions = null)
        {
            return new FileExtensions(iExtensions);
        }

#endregion

        /// <summary>
        /// 保护构造函数
        /// </summary>
        internal FileExtensions(List<FileExtension> iExtensions = null)
        {
            if (null == iExtensions || 0 >= iExtensions.Count)
            {
                AddElement(FileExtension.Create("*", "*"));
            }
            else
            {
                var count = iExtensions.Count;
                for (var idx = 0; idx < count; ++idx)
                {
                    var extension = iExtensions[idx];
                    if(null == extension || !extension.Valid) continue;
                    AddElement(extension);
                }
            }
        }
        
        /// <summary>
        /// 后缀列表
        /// </summary>
        public List<string> Extensions => list.Select(iO => $".{iO.Extension}").ToList();

        private string[] _browseExtensions = null;
        /// <summary>
        /// 浏览选项列表
        /// <para>* 文件后缀列表格式:{ "FileType", "FileExtensions" }</para>
        /// <para>* 如：{ "Image files", "png,jpg,jpeg" }</para>
        /// </summary>
        public string[] BrowseExtensions
        {
            get
            {
                if (null != _browseExtensions) return _browseExtensions;

                var browseExtensions = new List<string>();
                var count = list.Count;
                for (var idx = 0; idx < count; ++idx)
                {
                    var fileExt = list[idx];
                    if(null == fileExt || !fileExt.Valid) continue;
                    
                    browseExtensions.Add(fileExt.TitleDesc);
                    browseExtensions.Add(fileExt.Extension);
                }

                _browseExtensions = browseExtensions.ToArray();
                return _browseExtensions;
            }
        }
    }
    
    /// <summary>
    /// 过滤数据
    /// </summary>
    /// <typeparam name="TData">过滤数据类型</typeparam>
    [Serializable]
    public abstract class FilterData<TData> : JsonData<TData>, IFilterData
        where TData : JsonData, IFilterData
    {

        /// <summary>
        /// 保护构造函数
        /// </summary>
        /// <param name="iCompareOptions">比较选项</param>
        /// <param name="iExtensions">扩展列表</param>
        protected FilterData(int iCompareOptions = (int)HCompareOptions.None, IFileExtensions iExtensions = null) : base()
        {
            compareOptions = (int)iCompareOptions;
            extensions.Clear();
            if (null == iExtensions)
            {
                extensions.List.Add(FileExtension.Create("*.*", "*"));
            }
            else
            {
                extensions.ApplyData(iExtensions);
            }
        }

#region Options

        [SerializeField]
        private int compareOptions;
        /// <summary>
        /// 比较选项
        /// </summary>
        public int CompareOptions => compareOptions;
            
        /// <summary>
        /// 过滤选项 : 以XXX开头
        /// </summary>
        protected bool FilterStartWith => UtilsBytes.CheckBytes(compareOptions, (int)HCompareOptions.StartWith);
        
        /// <summary>
        /// 过滤选项 : 包含
        /// </summary>
        protected bool FilterContains => UtilsBytes.CheckBytes(compareOptions, (int)HCompareOptions.Contains);
        
        /// <summary>
        /// 过滤选项 : 以XXX结尾
        /// </summary>
        protected bool FilterEndsWith => UtilsBytes.CheckBytes(compareOptions, (int)HCompareOptions.EndsWith);
        
        /// <summary>
        /// 过滤选项 : 忽略大小写
        /// </summary>
        protected bool FilterIgnoreCase => UtilsBytes.CheckBytes(compareOptions, (int)HCompareOptions.IgnoreCase);
        
        /// <summary>
        /// 验证 : 等于
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:通过; false:不通过;</returns>
        protected virtual bool Verify(string iTarget)
        {
            if (string.IsNullOrEmpty(iTarget)) return false;
            
            // 若无扩展需求，则一律验证通过
            var extensionsTmp = Extensions.Extensions;
            if (null == extensionsTmp || 0 >= extensionsTmp.Count) return true;

            var toList = extensionsTmp;
            if (FilterIgnoreCase)
            {
                toList = toList.Select(iO => iO.ToLower()).ToList();
            }

            var flg = true;
            var target = FilterIgnoreCase ? iTarget.ToLower() : iTarget;
            var count = extensionsTmp.Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var extension = toList[idx];
                if(string.IsNullOrEmpty(extension)) continue;

                if (FilterStartWith)
                {
                    flg &= target.StartsWith(extension);
                }

                if (flg && FilterContains)
                {
                    flg &= target.Contains(extension);
                }

                if (flg && FilterEndsWith)
                {
                    flg &= target.EndsWith(extension);
                }
            }

            return flg;
        }

#endregion
        
#region Filter

        [SerializeField]
        private FileExtensions extensions = new FileExtensions();
        /// <summary>
        /// 过滤扩展选项
        /// <para>* 可以追加列入后缀名等信息</para>
        /// </summary>
        public IFileExtensions Extensions => extensions;

        /// <summary>
        /// 过滤
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:通过过滤; false:未通过过滤;</returns>
        public abstract bool Filter(string iTarget);
        
#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IFilterData filter)
            {
                compareOptions = UpdateValue(compareOptions, filter.CompareOptions, iImport);
                
                dirty = extensions.ApplyData(filter.Extensions);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            compareOptions = (int)HCompareOptions.None;
            extensions.Clear();
        }
    }
}
